package org.muninn.niagara.conversion;

import javax.baja.control.BEnumWritable;
import javax.baja.status.BStatusBoolean;
//import javax.baja.status.BStatusEnum;
import javax.baja.status.BStatus;
import javax.baja.status.BStatusNumeric;
import javax.baja.status.BStatusString;
import javax.baja.sys.BComponent;
import javax.baja.sys.BDynamicEnum;
import javax.baja.sys.BEnumRange;
import javax.baja.sys.BFacets;
import javax.baja.sys.BIcon;
import javax.baja.sys.Context;
import javax.baja.sys.Flags;
import javax.baja.sys.Property;
//import javax.baja.sys.Slot;
import javax.baja.sys.Sys;
import javax.baja.sys.Type;

/**
 * Converter block for organised display of redundant-line valve system status output (3- or 4-valve arrangements only). Also
 * produces alarm status based on a string of numbers representing all the possible error states of the system.
 *
 * @author Conor Freeland, Muninn Group
 * @creation Jan 2013
 */
public class BValveStatusConverter extends BComponent
{
  /** Array of String values for assigning facets to outputs */
  private static String[] keys = {"None", "Open", "Closed", "Moving", "ClosedWhenOpen", "OpenWhenClosed", "Both", "Neither"};
  private static int[] ordinals = {0, 1, 2, 3, 4, 5, 6, 7};
  
  /** Facet to be applied to all outputs */
  public static final Property facets = newProperty(Flags.SUMMARY, BFacets.makeEnum(BEnumRange.make(ordinals, keys)));
  public void setFacets(BFacets f) { set("facets", f); }
  public BFacets getFacets() { return (BFacets) get("facets"); }
  
  /** 3- or 4-digit numeric input */
  public static final Property input = newProperty(Flags.SUMMARY, new BStatusNumeric());
  public void setInput(BStatusNumeric v) { set(input, v); }
  public BStatusNumeric getInput() { return (BStatusNumeric) get(input); }
  
  /** Enumerated writable output #1 */
  public static final Property invOutput1 = newProperty(Flags.READONLY|Flags.SUMMARY, new BEnumWritable(), BFacets.makeEnum(BEnumRange.make(ordinals, keys)));
  /** Enumerated writable output #2 */
  public static final Property invOutput2 = newProperty(Flags.READONLY|Flags.SUMMARY, new BEnumWritable(), BFacets.makeEnum(BEnumRange.make(ordinals, keys)));
  /** Enumerated writable output #3 */
  public static final Property invOutput3 = newProperty(Flags.READONLY|Flags.SUMMARY, new BEnumWritable(), BFacets.makeEnum(BEnumRange.make(ordinals, keys)));
  /** Enumerated writable output #4 */
  public static final Property invOutput4 = newProperty(Flags.READONLY|Flags.SUMMARY, new BEnumWritable(), BFacets.makeEnum(BEnumRange.make(ordinals, keys)));
  
  public void setInvOutput1(BEnumWritable v) { set(invOutput1, v); }
  public void setInvOutput2(BEnumWritable v) { set(invOutput2, v); }
  public void setInvOutput3(BEnumWritable v) { set(invOutput3, v); }
  public void setInvOutput4(BEnumWritable v) { set(invOutput4, v); }
  
  public BEnumWritable getInvOutput1() { return (BEnumWritable) get(invOutput1); }
  public BEnumWritable getInvOutput2() { return (BEnumWritable) get(invOutput2); }
  public BEnumWritable getInvOutput3() { return (BEnumWritable) get(invOutput3); }
  public BEnumWritable getInvOutput4() { return (BEnumWritable) get(invOutput4); }
  
  /** String containing all alarm statuses */
  public static final Property alarmStates = newProperty(Flags.SUMMARY, "");
  public void setAlarmStates(String v) { setString(alarmStates, v); }
  public String getAlarmStates() { return getString(alarmStates); }
  
  /** Shared alarm status for all 4 outputs */
  public static final Property alarm = newProperty(Flags.READONLY|Flags.SUMMARY, new BStatusBoolean());
  public void setAlarm(BStatusBoolean v) { set(alarm, v); }
  public BStatusBoolean getAlarm() { return (BStatusBoolean) get(alarm); }
  
  private static String ALARMS;
  
  /** Location of the system */
  public static final Property Location = newProperty(Flags.SUMMARY, new BStatusString());
  public void setLocation(BStatusString v) { set(Location, v); }
  public BStatusString getLocation() { return (BStatusString) get(Location); }
  
  /** Tag for Valve 1 */
  public static final Property V1_Tag = newProperty(Flags.SUMMARY, new BStatusString());
  /** Tag for Valve 2 */
  public static final Property V2_Tag = newProperty(Flags.SUMMARY, new BStatusString());
  /** Tag for Valve 3 */
  public static final Property V3_Tag = newProperty(Flags.SUMMARY, new BStatusString());
  /** Tag for Valve 4 */
  public static final Property V4_Tag = newProperty(Flags.SUMMARY, new BStatusString());
  
  public void setV1_Tag(BStatusString v) { set(V1_Tag, v); }
  public void setV2_Tag(BStatusString v) { set(V2_Tag, v); }
  public void setV3_Tag(BStatusString v) { set(V3_Tag, v); }
  public void setV4_Tag(BStatusString v) { set(V4_Tag, v); }
  
  public BStatusString getV1_Tag() { return (BStatusString) get(V1_Tag); }
  public BStatusString getV2_Tag() { return (BStatusString) get(V2_Tag); }
  public BStatusString getV3_Tag() { return (BStatusString) get(V3_Tag); }
  public BStatusString getV4_Tag() { return (BStatusString) get(V4_Tag); }
  
  /** Init if started after steady state has been reached */
  public void started() { convert(); }

  /**
   * Set output on input change
   * @param p
   * @param cx
   */
  public void changed(Property p, Context cx)
  {
    if (!isRunning())
      return;

    if (p.equals(input) || p.equals(facets))
      convert();
  }
  
  /** Main operation method */
  public void convert()
  {
    ALARMS = getAlarmStates();
    String inputString = String.valueOf((int) getInput().getValue());
    BStatus status = getInput().getStatus();
    
    if (inputString.length() == 3)
    {
      getInvOutput1().setFacets(getFacets());
      getInvOutput2().setFacets(getFacets());
      getInvOutput3().setFacets(getFacets());
      
      getInvOutput1().getOut().setStatus(status);
      getInvOutput2().getOut().setStatus(status);
      getInvOutput3().getOut().setStatus(status);
      
      getInvOutput1().set(BDynamicEnum.make((int) (inputString.charAt(0) - '0')));
      getInvOutput2().set(BDynamicEnum.make((int) (inputString.charAt(1) - '0')));
      getInvOutput3().set(BDynamicEnum.make((int) (inputString.charAt(2) - '0')));
      
      if (ALARMS.indexOf(inputString.charAt(0)) != -1 ||
          ALARMS.indexOf(inputString.charAt(1)) != -1 ||
          ALARMS.indexOf(inputString.charAt(2)) != -1)
        getAlarm().setValue(true);
      else
        getAlarm().setValue(false);
    }
    
    if (inputString.length() == 4)
    {
      getInvOutput1().setFacets(getFacets());
      getInvOutput2().setFacets(getFacets());
      getInvOutput3().setFacets(getFacets());
      getInvOutput4().setFacets(getFacets());
      
      getInvOutput1().getOut().setStatus(status);
      getInvOutput2().getOut().setStatus(status);
      getInvOutput3().getOut().setStatus(status);
      getInvOutput4().getOut().setStatus(status);
      
      getInvOutput1().set(BDynamicEnum.make((int) (inputString.charAt(0) - '0')));
      getInvOutput2().set(BDynamicEnum.make((int) (inputString.charAt(1) - '0')));
      getInvOutput3().set(BDynamicEnum.make((int) (inputString.charAt(2) - '0')));
      getInvOutput4().set(BDynamicEnum.make((int) (inputString.charAt(3) - '0')));
      
      if (ALARMS.indexOf(inputString.charAt(0)) != -1 ||
          ALARMS.indexOf(inputString.charAt(1)) != -1 ||
          ALARMS.indexOf(inputString.charAt(2)) != -1 ||
          ALARMS.indexOf(inputString.charAt(3)) != -1)
        getAlarm().setValue(true);
      else
        getAlarm().setValue(false);
    }
  }
  
  public BIcon getIcon() { return icon; }
  private static final BIcon icon = BIcon.make("local:|module://muninn/org/muninn/niagara/graphics/MuninnGroup.PNG");

  public static final Type TYPE = Sys.loadType(BValveStatusConverter.class);
  public Type getType() { return TYPE; }
}